package net.protocol.diameter.avp;

import java.nio.ByteBuffer;

/**
 * This class provides a skeletal implementation of the {@link AVP} interface to
 * minimize the effort required to implement this interface.
 *
 * @author jinhongw@gmail.com
 */
public abstract class AbstractAVP<E> implements AVP<E> {
    public final static int DEFAULT_VENDOR_ID = 0;
    protected final static byte[] empty = new byte[4];

    private final DiameterAVPHeader header;

    /**
     * @param code       AVP Code
     * @param dataLength AVP Data Length
     */
    protected AbstractAVP(int code, int dataLength) {
    	this(code, DEFAULT_VENDOR_ID, dataLength);
    }

    /**
     * @param code       AVP Code
     * @param vendorId   Vendor-ID
     * @param dataLength AVP Data Length
     */
    protected AbstractAVP(int code, int vendorId, int dataLength) {
        this.header = new DiameterAVPHeader(code, vendorId, dataLength);
    }

    /**
     * Creates a new <code>AbstractAVP</code> with the given DiameterAVPHeader and source ByteBuffer
     *
     * @param header Diameter AVP Header
     * @param src The buffer from which bytes are to be retrieved
     */
    AbstractAVP(DiameterAVPHeader header, ByteBuffer src) {
        this.header = header;
    }

    @Override
    public ByteBuffer byteMe(ByteBuffer dst) {
        header.byteMe(dst);

        return dst;
    }

    @Override
    public int getCode() {
        return header.getCode();
    }

    @Override
    public int getVendorId() {
        return header.getVendorId();
    }

    @Override
    public boolean isVendorId() {
        return header.isVendorId();
    }

    @Override
    public boolean isMandatory() {
        return header.isMandatory();
    }

    @Override
    public boolean isProtected() {
        return header.isProtected();
    }

    @Override
    public void setMandatory(boolean flag) {
        header.setMandatory(flag);
    }

    @Override
    public void setProtected(boolean flag) {
        header.setProtected(flag);
    }

    @Override
    public int getLength() {
        return header.getLength();
    }

    @Override
    public int getHeaderLength() {
        return header.getHeaderLength();
    }

    @Override
    public int getDataLength() {
        return header.getDataLength();
    }

    protected abstract void detail(StringBuilder buf);

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AbstractAVP<?> other = (AbstractAVP<?>) obj;
        if (header == null) {
            if (other.header != null)
                return false;
        } else if (!header.equals(other.header))
            return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((header == null) ? 0 : header.hashCode());
        return result;
    }

    /**
     * <pre>
     * Converts this <code>AVP</code> to a formatted string.The string returned is of the form:
     *   AVP-Name (AVP-Code,V|M|P,v=Vendor-ID(opt),l=AVP-Length) = data
     *
     *   For example:
     *   	DiameterURI (1,VM,v=1,l=64) = aaa://127.0.0.1:3868;transport=tcp;protocol=diameter
     *   	Address (3868,M,l=14) = 10.60.3.78
     *
     *      Grouped (284,M,l=45) =
     *   	  DiameterIdentity (280,M,l=18) = Proxy-Host
     *   	  OctetString (33,M,l=19) = Proxy-State
     * </pre>
     *
     * @return a string representation of this <code>AVP</code>.
     */
    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append(getName());
        buf.append(" (");
        buf.append(header);
        buf.append(") = ");
        detail(buf);
        return buf.toString();
    }
}